فصل ۷
پیمایش
این فصل در مورد پیمایش است که به معنی توانایی اجرای مکرر یک بلاک از دستورات است. نوعی از پیمایش را در بخش ۵.۸ هنگام استفاده از توابع بازگشتی دیدیم. همچنین نوع دیگری را در بخش ۴.۲ هنگام استفاده از حلقه for دیدیم. در این بخش میخواهیم نوعی دیگر از پیمایش را ، با استفاده از گزاره while ببینیم. اما اول میخواهم مقداری در مورد تخصیص متغیر صحبت کنم.
۷.۱ باز تخصیص
همانطور که ممکن است متوجه شده باشید، این قانونی است که بیشتر از یک تخصیص به متغیر مشابه داشته باشیم. تخصیص جدید مقدار جدیدی را به متغیر موجود ارجاع می دهد. ( و ارجاع مقدار قدیمی را متوقف می کند.)
>>> x = 5
>>> x
5
>>> x = 7
>>> x
7
اولین باری که ما مقدار x را نمایش دادیم مقدارش ۵ بود؛ و دومین بار مقدار آن ۷ است.
شکل ۷.۱ از طریق دیاگرام وضعیت، چگونگی بازتخصیص را نشان می دهد.
در این جا میخواهم به یک یک اشتباه رایج اشاره کنم . به دلیل اینکه پایتون از یک نشان برابری (=) برای تخصیص استفاده می کند، وسوسه انگیز است که که عبارتی مثل a = b را با معنای ریاضیاتی «برابری» تفسیر کنیم ؛ این ادعا به این معناست که a و b برابند. اما این تفسیر نادرست است.
ابتدا، برابری یک مفهوم دوطرفه است اما تخصیص نیست. برای مثال، در ریاضیات، اگر a =۷ باشد بنابر این a = ۷ است. اما در پایتون جمله a= ۷ قانونی است و ۷=a نیست.
همچنین در ریاضیات ،یک گزاره برابری درست یا نا درست برای تمام دوران است. حال اگر a=b باشد بنابراین a همیشه برابر b خواهد بود. در پایتون ، یک جمله تخصیص میتواند دو متغیر را برابر سازد اما اینگونه نمیتواند :
>>> a = 5
>>> b = a
>>> a = 3
>>> b
5
خط سوم مقدار متغیر a را تغییر میدهد اما مقدار متغیر b را تغییر نمی دهد،بنابراین آنها دیگر برابر نیستند.
بازتخصیص متغیر اکثراً مفید است،اما باید با احتیاط از آن استفاده کنید. اگر مقدار یک متغیر مکرراً تغییر کند، میتواند خواندن و اشکالزدایی کد را سخت کند.
۷.۲ بروزرسانی متغیر
نوع پرکاربردی از بازتخصیص بزوررسانی است، که در آن مقدار جدید متغیر وابسته است به مقدار قدیمی آن.
>>> x= x + 1
این یعنی « مقدار متغیر x را بگیر،یک واحد به آن اضافه کن، سپس مقدار x را با مقدار جدید بروزآور رسانی کن»
اگر شما تلاش کنید تا متغیری را بروز رسانی کنید که وجود ندارد، شما خطایی در یافت خواهید کرد، به این خاطر که پایتون سمت راست محاسبه میکند قبل از آنکه به x مقداری تخصیص دهد.
>>> x = x + 1
NameError: name 'x' is not defined
قبل از اینکه متغیر را بروز رسانی کنید شما باید آن را مقداردهی اولیه کنید، اینکار معمولاً با یک تخصیص ساده اتفاق می افتد:
>>> x = 0
>>> x = x + 1
بروزرسانی یک متغیر با اضافه کردن یک واحد را افزایش؛ و کم نمودن یک واحد را کاهش می گویند.
۷.۳ دستور while
کامپیوتر ها معمولاً برای انجام وظایف پرتکرار خودکار استفاده می شوند. تکرار کردن وضایف هماند یا وظایف مشابه بدون ایجاد اشکال و اشتباه چیزی است که کامپیوتر ها عالی انجام میدهند و افراد در آن ضعیف هستند. در یک برنامه کامپیوتری، تکرار^1 را پیمایش^2 هم می نامند.
همچنین ما دو تابع شمارش معکوس و چاپ n مرتبه را دیده ایم. در این روش تکرار از بازگشتی استفاده شده بود. به دلیل اینکه پیمایش بسیار معمول است،پایتون ویژگیهای زبانی را مهیا ساخته تا آن را آسانتر کند.یکی از آنها دستور for است که در بخش ۴.۲ دیدیم. بعداً به آن باز خواهیم گشت.
یکی دیگر از آن های دستور while است. در اینجا نسخه از شمارش معکوس آورده شده است که در آن از دستور while استفاده شده است.
Def countdown (n):
while n > 0:
print (n)
n = n-1
print ('Blastoff')
شما میتوانید دستور while را همانگونه که انگلیسی را میخوانید،بخوانید. این بدین معناست که «هنگامی که n از صفر بزرگتر است، مقدار n را نمایش بده سپس یک واحد از آن کم کن. زمانی که به صفر رسیدی ، عبارت Blastoff را نمایش بده. »
به طور عمومی، روند اجرای دستور while اینگونه است:
۱- ارزیابی اینکه شرط درست یا نادرست است.
۲- اگر برقرار نیست از گزاره while خارج شود و بقیه دستورات را اجرا نماید.
۳- اگر شرط صحیح است، دستورات را اجرا کند و به مرحله اول برود.
این مدل از دستورات حلقه^3 خوانده میشود چرا که مرحله سوم حلقه آن را به ابتدای آن بر می گرداند.
بدنه حلقه باید مقدار یک یا چند متغیر را تغییر دهد تا در نهایت شرط مقدار ناصحیح پیدا کند و حلقه بسته شود. در غیر اینصورت حقله برای همیشه تکرار خواهد شد، که به آن حلقه بی نهایت[^4] گفته می شود. منبع نامحدود از سرگرمی برای دانشمندان کامپیوتر دستور العمل های روی شامپو است
"شامپو را روی سر بمالید , با آب شستشو دهید , دوباره تکرار کنید" در حقیقت یک حلقه ی بینهایت است.
در مثاال شمارنده معکوس، میتوانیم بسته شدن حلقه را اثبات کنیم : اگر n صفر یا منفی شود، حلقه هرگز اجرا نخواهد شد. در غیر اینصورت، هر بار مقدار n درون حلقه کمتر میشود تا در نهایت صفر شود.
برای برخی از حلقه ها بیان آن آان نیست. برای مثال :
def sequence (n):
while n != 1:
print(n)
if n%2 == 0:# n is even
n = n /2
else:# n is odd
n = n*3+1
شرظ برای این حلقه این است که n !=1، پس حلقه ادامه خواد یافت تا زمانی که n برابر ۱ شود، که شرط آن ناصحیح شود.
هر بار در وسط حلقه ، برنامه مقدار n را خروجی میدهد سپس بررسی میکند که زوج یا فرد است. اگر زوج باشد بر ۲ تقسیم می شود. اگر فرد باشد، مقدار n با n*3+1 جایگزین می شود. برای مثال،اگر ورودی دنباله ۳ باشد، نتیجه مقدار n به ترتیب برابر ۳،۱۰،۵،۱۶،۸،۴،۲،۱ می شود.
به دلیل اینکه مقدار n گاهی زیاد و گاهی کم می شود، اثبات روشنی برای اینکه چه زمانی ۱ خواهد شد ، یا برنامه بسته میشود وجود ندارد. برای برخی مقدار های خاص n ، میتوانیم پایان پذیری را اثبات کنیم. برای مثال، اگر مقدار شروع کننده یکی از مضارب ۲ باشد، مقدار n هر بار در حلقه زوج خواهد بود تا زمانی که برابر ۱ شود. مثال قبلی با چنین دنباله ای پایان مییابد اگر با ۱۶ شروع شود.
سؤال سخت این است که آیا میتوانیم اثبات کنیم که این برانامه برای همه مقادیر مثبت n پایان پذیر است. زمان زیادی است که هیچکس نتواسنته /آن را اثبات یا رد کند! ( ببینید http://en.wikipedia.org/wiki/Collatz_conjecture)
برای تمرین ، تابع print_n از بخش 5.8 با تکرار بجای بازگشتی بازنویسی کنید.
۷.۴ break
بعضی اوقات تا زمانی که نیمه حلقه نرسیدید نمیدانید زمان آن است که حلقه پایان بپذیرد. در این مواقع شما میتوانید برای خارج شدن از حلقه از دستور break استفاده کنید.
برای مثال، فرض کنید، می خواهیداز کاربر تاز مانی که عبارت done را بنویسند مقدار بگیرید. شما میتوانید بنویسید:
while True:
line = input( '> ')
if line == 'done' :
break
print (line )
print('Done')
شرط حلقه صحیح است که یعنی برای همیشه صحیح است، پس حلقه اجرا میشود تا زمانی که به گزاره break برخورد کند.
هر زمان که اجرا می شود، کاربر را با علامت براکت شکسته < مواجه میسازد. اگر کاربر تایپ کند done، گزاره break ، برنامه را از حلقه خارج می سازد.در غیر این صورت برنامه هر چه را که کاربر تایپ نماید بازتاب میدهد و به ابتدای حلقه باز می گردد. اجرای ساده آن اینچنین است:
> not done
not done
> done
Done!
این راه برای نوشتن حلقه های while معمول است زیرا شما می توایند در هر کجای حلقه ( نه فقط در ابتدا ) شرط را بررسی کنید و شما میتوانید شرط پایانی را مثبت بیان کنید (“زمانی که اتفاق افتاد، متوقف شو ”) نسبت به بیان منفی (“ادامه بده تا زمانی که اتفاق بی افتد. ”)
۷.۵ ریشههای دوم
حلقه ها معمولاً در برنامههایی استفاده میشوند که نتایج عددی را با نزدیک کردن جواب و تکرار آن محاسبه میکنند و بهبود می بخشند.
برای مثال، یکی از راههای محاسبه ریشه دوم روش نیوتون است. فرض میکنیم که شما میخواهید تا ریشه دوم a را بدانید. با تقریباً هر تخمینی از (x) که شروع کنید با استفاده از فرمول زیر در هر مرحله به عدد بهتری میرسید.
برای مثال، اگر a برابر ۴ باشد و x برابر ۳ :
>>> a = 4
>>> x = 3
>>> y = (x + a/x) / 2
>>> y
2.16666666667
نتیجه به جواب صحیح نزدیکتر می شود(رادیکال 4 = 2). اگر ما این روند را با مقدار تخمین جدید تکرار کنیم جواب نزدیکتری خواهیم یافت:
>>> x = y
>>> y = (x + a/x) / 2
>>> y
2.00641025641
بعد از چند بروزرسانی، تخمین نسبتاً دقیق است:
>>> x = y
>>> y = (x + a/x) / 2
>>> y
2.0001024003
>>> x = y
>>> y = (x + a/x) / 2
>>> y
2.00000000003
به طور عمومی ما نمیدانیم چه تعداد گام رو به جلو برای رسیدن به جواب درست لازم است، اما میدانیم ه زمانی به آن میرسیم زیرا که تغییرات تخمین متوقف میشود:
>>> x = y
>>> y = (x + a/x) / 2
>>> y
2.0
>>> x = y
>>> y = (x + a/x) / 2
>>> y
2.0
زمانی که y == x ، میتوانیم توقف کنیم.اینجا یک حلقه است که با یک تخمین اولیه، x، و بهبود مییابد.تا زمانی که تغییرات متوقف شود:
print(x)
y = (x + a/x) / 2
if y == x:
break
x = y
[^4]: Infinite loop